#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <unistd.h>

static char *fmt_file_type(mode_t mode)
{
    if (S_ISREG(mode))
        return "regular file";
    if (S_ISDIR(mode))
        return "directory";
    if (S_ISLNK(mode))
        return "symbolic link";
    if (S_ISFIFO(mode))
        return "FIFO";
    if (S_ISCHR(mode))
        return "character device";
    if (S_ISBLK(mode))
        return "block device";
    if (S_ISSOCK(mode))
        return "socket";
    return "unknown";
}

int main(int argc, char *argv[])
{
    int fd;
    struct iovec iov[3], iov_rd[3];
    ssize_t nr, nw;
    size_t total_len = 0;

    char *buf = "Hello, ";
    int value = 123;
    struct stat statbuf;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        exit(1);
    }

    fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        exit(1);
    }
    
    iov[0].iov_base = buf;
    iov[0].iov_len = strlen(buf) + 1;
    total_len += iov[0].iov_len;
    iov[1].iov_base = &value;
    iov[1].iov_len = sizeof(value);
    total_len += iov[1].iov_len;

    if (fstat(fd, &statbuf) == -1) {
        perror("fstat");
        exit(1);
    }
    iov[2].iov_base = &statbuf;
    iov[2].iov_len = sizeof(statbuf);
    total_len += iov[2].iov_len;
    
    nw = writev(fd, iov, 3);
    if (nw == -1) {
        perror("writev");
        exit(1);
    }
    printf("wrote %zd bytes\n", nw);

    if (lseek(fd, 0, SEEK_SET) == -1) {
        perror("lseek");
        exit(1);
    }

    // 为读取分配内存
    char *read_buf = malloc(strlen(buf) + 1);
    if (read_buf == NULL) {
        perror("failed to allocate read buffer");
        exit(1);
    }
    int read_value;
    struct stat read_statbuf;

    iov_rd[0].iov_base = read_buf;
    iov_rd[0].iov_len = strlen(buf) + 1;
    iov_rd[1].iov_base = &read_value;
    iov_rd[1].iov_len = sizeof(read_value);
    iov_rd[2].iov_base = &read_statbuf;
    iov_rd[2].iov_len = sizeof(read_statbuf);

    nr = readv(fd, iov_rd, 3);
    if (nr == -1) {
        perror("readv");
        exit(1);
    }
    printf("read %zd bytes\n", nr);
    printf("buf: %s\n", (char *)iov_rd[0].iov_base);
    printf("value: %d\n", *(int *)iov_rd[1].iov_base);
    struct stat *statbuf_rd = (struct stat *)iov_rd[2].iov_base;
    printf("stat.st_size: %ld\n", statbuf_rd->st_size);
    printf("stat.st_ino: %ld\n", statbuf_rd->st_ino);
    printf("stat.st_mode: 0%o\n", statbuf_rd->st_mode);
    printf("file type: %s\n", fmt_file_type(statbuf_rd->st_mode));
    printf("permission: 0%o\n", statbuf_rd->st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
    printf("owner permission: 0%o\n", statbuf_rd->st_mode & S_IRWXU);
    printf("group permission: 0%o\n", statbuf_rd->st_mode & S_IRWXG);
    printf("other permission: 0%o\n", statbuf_rd->st_mode & S_IRWXO);
    printf("stat.st_nlink: %ld\n", statbuf_rd->st_nlink);
    printf("stat.st_uid: %d\n", statbuf_rd->st_uid);
    printf("stat.st_gid: %d\n", statbuf_rd->st_gid);
    printf("stat.st_rdev: %ld\n", statbuf_rd->st_rdev);
    printf("stat.st_blksize: %ld\n", statbuf_rd->st_blksize);
    printf("stat.st_blocks: %ld\n", statbuf_rd->st_blocks);
    printf("stat.st_atime: %ld\n", statbuf_rd->st_atime);
    printf("stat.st_mtime: %ld\n", statbuf_rd->st_mtime);
    printf("stat.st_ctime: %ld\n", statbuf_rd->st_ctime);
    
    free(read_buf);
    close(fd);
    return 0;
}